﻿using HRX.PayCenter.ApplicationCore.Interfaces;
using HRX.PayCenter.ApplicationCore.Services;
using HRX.PayCenter.Infrastructure.Data;
using HRX.PayCenter.Infrastructure.Logging;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Text;
using OSS.PaySdk.Ali;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using OSS.Http;
using OSS.PaySdk.Ali.Pay;
using HRX.PayCenter.ApplicationCore;
using HRX.PayCenter.Web.Middlewares;
using HRX.PayCenter.Common.WebAppBase;
using HRX.PayCenter.ApplicationCore.Configs;

namespace HRX.PayCenter.Web
{
    /// <summary>
    /// 启动项
    /// </summary>
    public class Startup
    {
        private IServiceCollection _services;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="configuration"></param>
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        /// <summary>
        /// 配置
        /// </summary>
        public IConfiguration Configuration { get; }

        //public void ConfigureDevelopmentServices(IServiceCollection services)
        //{
        //    // use in-memory database
        //    ConfigureInMemoryDatabases(services);

        //}

        //private void ConfigureInMemoryDatabases(IServiceCollection services)
        //{
        //    // use in-memory database
        //    services.AddDbContext<CatalogContext>(c =>
        //        c.UseInMemoryDatabase("Catalog"));

        //    ConfigureServices(services);
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        //public void ConfigureProductionServices(IServiceCollection services)
        //{
        //    // use real database
        //    // Requires LocalDB which can be installed with SQL Server Express 2016
        //    // https://www.microsoft.com/en-us/download/details.aspx?id=54284
        //    services.AddDbContext<CatalogContext>(c =>
        //        c.UseSqlServer(Configuration.GetConnectionString("CatalogConnection")));

        //    ConfigureServices(services);
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<CatalogContext>(c =>
              c.UseSqlServer(Configuration.GetConnectionString("CatalogConnection")));

            services.AddScoped(typeof(IRepository<>), typeof(EFRepository<>));
            services.AddScoped(typeof(IAsyncRepository<>), typeof(EFRepository<>));
            services.AddScoped<IAlipayOrderRepository, AlipayOrderRepository>();
            services.AddScoped<IRefundRepository, RefundRepository>();
            services.AddScoped<IDiviseRepository, DiviseRepository>();

            services.AddScoped<IPayService, AlipayTradeService>();
            services.AddScoped<IRouteService, RouteService>();
            services.AddScoped<IDeviceApiExternalService, ExternalService.Device.CallApiService>();

            services.Configure<ZPayConfigWrapper>(Configuration);
            services.Configure<PayCenterConfigWarpper>(Configuration);
            services.Configure<DeviceCallApiConfigWarpper>(Configuration);

            services.AddSingleton(typeof(IAppLogger<>), typeof(LoggerAdapter<>));

            // Add memory cache services
            //services.AddMemoryCache();

            services.AddSingleton<ZPayTradeApi>();
            services.AddSingleton<ZPayTransferApi>();
            services.AddSingleton<ZPayRefundApi>();
            services.AddSingleton<HttpManager>();

            services.AddHttpClient();

            services.AddSingleton<ILoggerFactory, LoggerFactory>();
            services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
            services.AddLogging(builder => builder.SetMinimumLevel(LogLevel.Trace));
            services.AddSwaggerConfig(Configuration.Get<SwaggerSettingsConfigWrapper>()?.SwaggerSettings);
            services.AddMvc()
                .SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);

            _services = services;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="loggerFactory"></param>
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                ListAllRegisteredServices(app);
            }
            else
            {
                app.UseHsts();
            }

            loggerFactory.AddNLog(new NLogProviderOptions
            {
                CaptureMessageTemplates = true,
                CaptureMessageProperties = true
            });

            //全局跟踪
            app.UseMiddleware(typeof(GlobalHandlingMiddleware));

            app.UseStaticFiles();
            app.UseSwagger(loggerFactory);
            app.UseMvc();
        }

        private void ListAllRegisteredServices(IApplicationBuilder app)
        {
            app.Map("/allservices", builder => builder.Run(async context =>
            {
                var sb = new StringBuilder();
                sb.Append("<h1>All Services</h1>");
                sb.Append("<table><thead>");
                sb.Append("<tr><th>Type</th><th>Lifetime</th><th>Instance</th></tr>");
                sb.Append("</thead><tbody>");
                foreach (var svc in _services)
                {
                    sb.Append("<tr>");
                    sb.Append($"<td>{svc.ServiceType.FullName}</td>");
                    sb.Append($"<td>{svc.Lifetime}</td>");
                    sb.Append($"<td>{svc.ImplementationType?.FullName}</td>");
                    sb.Append("</tr>");
                }
                sb.Append("</tbody></table>");
                await context.Response.WriteAsync(sb.ToString());
            }));
        }
    }
}
